package com.antd.common.auth.config;

import com.antd.common.auth.handler.AntdAccessDeniedHandler;
import com.antd.common.auth.handler.AntdAuthenticationEntryPoint;
import com.antd.common.auth.properties.IgnoreUrlPropertiesConfig;
import com.antd.common.auth.security.AntdUserDetails;
import com.antd.common.auth.token.AntdJwtAccessTokenConverter;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import java.util.Arrays;
import java.util.Map;

/**
 * TODO
 *
 * @author 子丶沫
 * @version 1.0
 * @date 2020/11/18 15:24
 */
@Slf4j
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Value("${resourceId}")
    private String resourceId;
    @Autowired
    private IgnoreUrlPropertiesConfig ignoreUrlPropertiesConfig;
    @Override
    public void configure(HttpSecurity http) throws Exception {
        for (String url : ignoreUrlPropertiesConfig.getUrls()) {
            System.out.println(url);
            http.authorizeRequests().antMatchers(url).permitAll();
        }
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                // 短信登录配置
                .and().csrf().disable();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(resourceId)
                .tokenServices(tokenServices())
                .authenticationEntryPoint(new AntdAuthenticationEntryPoint())
                .accessDeniedHandler(new AntdAccessDeniedHandler());

    }
    @Bean
    public JwtTokenStore jwtTokenStore(){
        return new JwtTokenStore(tokenConverter());
    }
    @Primary
    @Bean
    public DefaultTokenServices tokenServices() {
        TokenEnhancerChain tokenEnhancerChain=new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(),tokenConverter()));
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(jwtTokenStore());
        defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);
        return defaultTokenServices;

    }
    @Bean
    public JwtAccessTokenConverter tokenConverter(){
        JwtAccessTokenConverter jwtAccessTokenConverter = new AntdJwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("antd");
        return jwtAccessTokenConverter;
    }
    @Bean
    public TokenEnhancer tokenEnhancer(){
        return (accessToken, authentication) -> {
            AntdUserDetails userDetails=(AntdUserDetails) authentication.getPrincipal();
            Map<String, Object> param= Maps.newHashMap();
            param.put("userId",userDetails.getUserId());
            param.put("userName",userDetails.getUsername());
            param.put("authorities",userDetails.getAuthorities());
            ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(param);
            return accessToken;
        };
    }
}
